package com.inspur.edp.bef.builtincomponents.auth;

import com.inspur.edp.bef.api.BefRtBeanUtil;
import com.inspur.edp.bef.api.be.IBEContext;
import com.inspur.edp.bef.api.exceptions.BefFuncPermissionDeniedException;
import com.inspur.edp.bef.api.lcp.AuthInfo;
import com.inspur.edp.cef.api.authority.AuthFilter;
import com.inspur.edp.cef.api.authority.AuthorityInfo;
import com.inspur.edp.cef.api.authority.AuthorityInfoType;
import com.inspur.edp.cef.api.repository.DbParameter;
import com.inspur.edp.cef.entity.condition.ExpressRelationType;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.sys.perm.dataperm.runtime.api.manager.DataPermRuntimeService;
import io.iec.edp.sys.permrule.extend.api.entity.PermParamDataEntity;
import io.iec.edp.sys.permrule.extend.api.entity.PermResultExpress;
import io.iec.edp.sys.permrule.extend.api.entity.PermRuleParseResultEntity;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Priority;
import org.springframework.util.StringUtils;

//适用于OA场景的权限控制
@Priority(100)
public class OAStyleDataPermissionController implements
    com.inspur.edp.bef.spi.auth.DataPermissionController<OAStyleDataPermissionCache> {

  @Override
  public String getName() {
    return "PF_OAStyleDataPermissionController";
  }

  @Override
  public OAStyleDataPermissionCache buildCache() {
    return new OAStyleDataPermissionCache();
  }

  @Override
  public boolean checkDataAuthority(String actionCode, IBEContext beContext,
      AuthInfo authInfo, OAStyleDataPermissionCache cache) {
    //isHasDataPermission实现中调用了被关联模型的lcp.retrieve,不管当前动作是什么都会被覆盖为retrieve导致控制结果不正确, 暂用session隔离的方式避免动作编号互相影响.
    BefRtBeanUtil.getBefSessionManager().createSession(Duration.ofSeconds(20));
    try {
      Boolean permissionRez = getDataPermissionManager().isHasDataPermission(
          beContext.getCurrentData(), authInfo.getExtend2(), actionCode);
      return permissionRez;
    }finally {
      BefRtBeanUtil.getBefSessionManager().closeCurrentSession();
    }
  }

  @Override
  public List<AuthorityInfo> getQueryAuthInfo(AuthInfo authInfo,
      OAStyleDataPermissionCache cache) {
    PermRuleParseResultEntity ruleResult = getDataPermissionManager().getPermFilterExpressByRule(authInfo.getExtend2(), "Query");//TODO:需要rpc调用
    switch(ruleResult.getPermRuleParseResultType()) {
      case ALLPerm:
        return Collections.emptyList();
      case NOPerm:
        throw new BefFuncPermissionDeniedException();
      case Express:
        return convertExpress2Filter(ruleResult);
      default://TODO: querySql暂不支持
        throw new RuntimeException("not supported PermRuleParseResultType" + ruleResult.getPermRuleParseResultType());
    }
  }

  private static List<AuthorityInfo> convertExpress2Filter(PermRuleParseResultEntity ruleResult) {
    if(ruleResult.getPermResultExpressList() == null || ruleResult.getPermResultExpressList().isEmpty()) {
      return Collections.emptyList();
    }
    AuthorityInfo authInfo = new AuthorityInfo();
    authInfo.setAuthType(AuthorityInfoType.Filter);
    List<AuthFilter> filters = new ArrayList<>(ruleResult.getPermResultExpressList().size());
    for (PermResultExpress permResultExpress : ruleResult.getPermResultExpressList()) {
      filters.add(convertExpress2Condition(permResultExpress));
    }
    authInfo.setFilter(filters);
    if(ruleResult.getParameters() != null && !ruleResult.getParameters().isEmpty()) {
      authInfo.setFilterParameters(convertAuthParameters(ruleResult.getParameters()));
    }
    List<AuthorityInfo> rez = new ArrayList<>(1);
    rez.add(authInfo);
    return rez;
  }

  private static List<DbParameter> convertAuthParameters(Map<Integer, PermParamDataEntity> pars) {
    List<DbParameter> rez = new ArrayList<>(pars.size());
    for (int i = 0; i < pars.size(); i++) {
      PermParamDataEntity par = pars.get(i);
      rez.add(new DbParameter(par.getColumnName(), null, par.getColumnValue()));
    }
    return rez;
  }

  private static AuthFilter convertExpress2Condition(PermResultExpress permResultExpress) {
    AuthFilter rez = new AuthFilter();
    rez.setFilterBody(convert2ExpressBody(permResultExpress));
    rez.setColumnName(permResultExpress.getField());
    rez.setRelationType(convert2ExpressRelation(permResultExpress.getRelation()));
    return rez;
  }

  private static String convert2ExpressBody(PermResultExpress permResultExpress) {
    String compare = Objects.requireNonNull(permResultExpress.getCompare(), "PermResultExpress.getCompare()");

    switch(compare) {
      case PERM_COMPARE_LIKE:
        return compare + " '%" + permResultExpress.getValue() + "%'";
      default:
        return compare + permResultExpress.getValue();
    }
  }

  private static ExpressRelationType convert2ExpressRelation(String relationStr) {
    if (StringUtils.isEmpty(relationStr)) {
      return ExpressRelationType.Empty;
    }
    switch(relationStr.trim().toLowerCase()) {
        case PERM_RELATION_AND:
          return ExpressRelationType.And;
        case PERM_RELATION_OR:
          return ExpressRelationType.Or;
        default:
          throw new RuntimeException("不支持的过滤条件关系类型" + relationStr);
      }
  }

  private static volatile DataPermRuntimeService dataPermissionManager;

  private static DataPermRuntimeService getDataPermissionManager() {
    if (dataPermissionManager == null) {
      dataPermissionManager = SpringBeanUtils.getBean(DataPermRuntimeService.class);
//    //TOOD: 不可签入
//      new DataPermRuntimeService() {
//        @Override
//        public PermRuleParseResultEntity getPermFilterByRule(String s, String s1) {
//          PermRuleParseResultEntity rez = new PermRuleParseResultEntity();
//          rez.setPermRuleParseResultType(PermRuleParseResultType.FilterSQL);
//          List<PermResultExpress> expressList = new ArrayList<>(2);
//
//          PermResultExpress e1 = new PermResultExpress();
//          e1.setCompare("<>");
//          e1.setField("ID");
//          e1.setValue("?0");
//          e1.setExpressType(PermResultExpressType.Value);
//          e1.setRelation("and");
//          expressList.add(e1);
//
//          PermResultExpress e2 = new PermResultExpress();
//          e2.setCompare("<>");
//          e2.setField("ID");
//          e2.setValue("?1");
//          e2.setExpressType(PermResultExpressType.Value);
//          expressList.add(e2);
//          rez.setPermResultExpressList(expressList);
//
//          Map<Integer,  PermParamDataEntity> pars = new HashMap<>(4);
//          pars.put(0, new PermParamDataEntity("ID", "001532c9-7212-4e75-801f-c0ba53442c5c"));
//          pars.put(1, new PermParamDataEntity("ID", "testAuthIdValue2"));
//          rez.setParameters(pars);
//          return rez;
//        }
//
//        @Override
//        public Boolean isHasDataPermission(Object o, String s, String s1) {
//          return true;
//        }
//      };
    }
    return dataPermissionManager;
  }

  private static final String PERM_COMPARE_LIKE = "like";

  private static final String PERM_RELATION_AND = "and";
  private static final String PERM_RELATION_OR = "or";
}
